package prototype;

import java.util.*;
import java.util.HashMap;

public class CompositGate extends DigitalGate {

    public HashMap<Integer, DigitalGate> gateList = new HashMap<Integer, DigitalGate>();
    public HashMap<Integer, Generator> generatorList = new HashMap<Integer, Generator>();
    private HashMap<Integer, ArrayList<Integer[]>> inMapping = new HashMap<Integer, ArrayList<Integer[]>>();
    private HashMap<Integer, Integer[]> outMapping = new HashMap<Integer, Integer[]>();
    /*
    <portmap>
    <inmap outPort="0" in="0" inPort="0" />
    <inmap outPort="1" in="0" inPort="1" />
    <inmap outPort="1" in="1" inPort="1" />
    <outmap inPort="0" out="1" outPort="0" />
    </portmap>
     */
     //konstruktor
    public CompositGate(int MaxInputPort, int MaxOutputPort, HashMap<Integer, ArrayList<Integer[]>> _inMapping, HashMap<Integer, Integer[]> _outMapping) {
        super(MaxInputPort, MaxOutputPort);

        //mappingek beallitasa
        inMapping = _inMapping;
        outMapping = _outMapping;
    }

    //generator hozzaadas
    public void addGenerator(Integer id, Generator generator) {
        generatorList.put(id, generator);
    }

    //kapu hozzaadas
    public void addGate(Integer id, DigitalGate gate) {
        gateList.put(id, gate);
    }

    @Override
    public void addOutput(int port, Wire output) throws Exception {
        //port valtozoban van a transzparens kimeneti portunk
        //megkeressuk melyik belso elem illetve annak melyik portja tartozik ehhez
        //ez egyertelmuen meghatarozhato
        super.addOutput(port, output);
        Integer[] id = outMapping.get(port);

        //2 tagu id, elso tagja az elem id ja a masodik az elem portja
        //atvezetjuk az osszekottetest
        //ha generatorrol van szo
        if (generatorList.containsKey(id[0])) {
            generatorList.get(id[0]).addOutput(id[1], output);
        } else {
            gateList.get(id[0]).addOutput(id[1], output);
        }
    }

    @Override
    public void addInput(int port, Wire input) throws Exception {
        //port tartalmazza a bejovo transzparens portot
        //ki van rakotve erre a porta
        ArrayList<Integer[]> temp = inMapping.get(port);

        super.addInput(port, input);

        //mindenkit bekotunk
        for (int i = 0; i < temp.size(); i++) {
            //get the gate info
            Integer[] a = (Integer[]) temp.get(i);

            //make the connection
            gateList.get(a[0]).addInput(a[1], input);
        }
    }

    @Override
    public void gateLogic() throws Exception {
        //regi kimenetek lementese
        ArrayList<Sign> results = new ArrayList<Sign>();
        
        Set<Integer> tempSet = outputList.keySet();
        for (Integer integer : tempSet) {
            ArrayList<Wire> t = outputList.get(integer);
            for (Wire wire : t) {
                results.add(wire.getDigitalValue());
            }
        }

        //gate logikak hivasa
        try {
            for (int i = 0; i < 50; i++) {
                for (int j = 0; j < gateList.size(); j++) {
                    gateList.get(j).gateLogic();
                }
            }
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }

        //eredmeny ellenorzes, ugyanolyan sorrendben megyunk vegig igy ellenorizve
        int i=0;
        for (Integer integer : tempSet) {
            ArrayList<Wire> t = outputList.get(integer);
            for (Wire wire : t) {
                if (wire.getDigitalValue() != results.get(i))
                {
                    //valtozas jelentese
                    setChanged();
                    notifyObservers("StateChanged");
                    return;
                }
                i++;
            }
        }
    }

    @Override
    public ElementType getType() {
        //tipus : composit
        return ElementType.Composit;
    }
}
